/* 
Scenic Graphics Library
Copyright (C) 2007 Jouni Tulkki

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USApackage scenic;
*/

#include <stdlib.h>
#include <string.h>

#include "Debug.h"
#include "DynArray.h"


static DynArray<FunctionObject*> functionObjects;


FunctionObject::FunctionObject(char *name)
{
	this->name = name;
	executionTime = 0;
	callCount = 0;
	if(functionObjects.size == 0)
		atexit(printProfilingInformation);
	functionObjects.add(this);
}

static int compareTime(const void *a, const void *b)
{
	FunctionObject *fa = *(FunctionObject**)a;
	FunctionObject *fb = *(FunctionObject**)b;

	if(fa->executionTime > fb->executionTime)
		return -1;
	if(fa->executionTime < fb->executionTime)
		return 1;
	return 0;
}

void FunctionObject::printProfilingInformation()
{
	__int64 totalTime = 0;
	__int64 cumulativeTime = 0;
	int i, j, k;
	FunctionObject **functions = new FunctionObject*[functionObjects.size];
	FunctionObject **functions2 = new FunctionObject*[functionObjects.size];

	memcpy(functions, functionObjects.data, functionObjects.size * sizeof(FunctionObject*));	
	qsort(functions, functionObjects.size, sizeof(FunctionObject*), compareTime);
	
	j = 0;
	for(i = 0; i < functionObjects.size; i++) 
	{
		FunctionObject *f = functions[i];
		char *ext = strchr(f->name, '.');
		
		if(!ext)
		{
			functions2[j++] = f;
			for(k = 0; k < functionObjects.size; k++) 
			{
				FunctionObject *f2 = functionObjects[k];
				char *ext2 = strchr(f2->name, '.');
				
				if(ext2 && strncmp(f2->name, f->name, ext2 - f2->name) == 0)
					functions2[j++] = f2;
					
			}
		}
	}

	for(i = 0; i < functionObjects.size; i++)
	{
		FunctionObject *f = functionObjects[i];
		
		if(!strchr(f->name, '.'))
			totalTime += f->executionTime;
	}

	printf("=== PROFILING INFORMATION ===\n");
	printf("Name                                                Time CumTime Ticks (k)  Calls      Ticks/Call\n"); 
	for(i = 0; i < functionObjects.size; i++)
	{
		FunctionObject *f = functions2[i];
		char temp[1000];

		if(strchr(f->name, '.'))
		{
			strcpy(temp, "  ");
			strcat(temp, f->name);
		}
		else
		{
			strcpy(temp, f->name);
			cumulativeTime += f->executionTime;
		}
		printf("%-50s %4.1lf%%  %5.1lf%% %-10d %-10d %-10d\n", 
			temp, 
			100.0 * f->executionTime / totalTime,
			100.0 * cumulativeTime / totalTime,
			(int)(f->executionTime / 1000),
			(int)(f->callCount),
			(int)(f->executionTime / f->callCount)
			);
	}
	
	delete functions;
	delete functions2;
}

// #define TRACE_FUNCTIONS 1

//#include <pthread.h>

FunctionExecutionObject::FunctionExecutionObject(FunctionObject *function)
{
	this->function = function;
#ifdef TRACE_FUNCTIONS
//	printf("ENTER %s (thread=%d)\n", function->getName(), pthread_self()); 
	printf("ENTER %s\n", function->getName()); 
#endif
	function->callCount++;
	startTime = readTimeStampCounter();
}

FunctionExecutionObject::~FunctionExecutionObject()
{
	function->executionTime += readTimeStampCounter() - startTime;
#ifdef TRACE_FUNCTIONS
	printf("LEAVE\n");
#endif
}
